/*
最新代码，以 https://gitee.com/yiliangwu880/CppProto.git 项目为准。
网络使用例子： https://gitee.com/yiliangwu880/rpc_libevent_cpp.git 
功能： cpp进程间RPC。 回调的方式使用
详情：
	原理： 
		svr 注册id,绑定函数。 
		client 请求服务器的消息为：fun_id, snid, 可变参数。 
		svr 返回 1或者其他特殊值, snid, 可变参数。

	协议结构：
	client req: sessionId, funId, Args ...
	svr rsp:sessionId, return Args ...

*/
#pragma once
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <deque>
#include <tuple>
#include <sys/time.h>
#include "ProtoMarco.h"


const size_t MAX_NET_BUF_LEN = 1024 * 10;
const uint32_t MAX_RPC_CACHE_SN_NUM = 1000;
const uint64_t RPC_TIME_OUT_SEC = 3 * 60;
//fun_id 特殊值：
const uint32_t RPC_INIT_ID      = 0; //client请求svr初始化
const uint32_t RPC_RSP_ID       = 1; //server 响应给 client
const uint32_t RPC_RSP_ERROR_ID = 2; //server 响应给 client 错误日志
const uint32_t CUSTOM_FUN_ID    = 3; //用户定义服务器函数的开始ID
namespace rpc
{
	extern char gbuf[MAX_NET_BUF_LEN];
}

template<class Fun, typename Tuple, std::size_t... Is>
void CallByTupleImpl(Fun f, const Tuple& t, std::index_sequence<Is...>)
{
	f(std::get<Is>(t)...);
}

template<class Fun, typename... Args>
void CallByTuple(Fun f, const std::tuple<Args...>& t)
{
	CallByTupleImpl(f, t, std::index_sequence_for<Args...>{});
}

template<typename ReturnType, typename... Args, typename Tuple, std::size_t... Is>
ReturnType CallByTupleImplRet(ReturnType(*f)(Args...), const Tuple& t, std::index_sequence<Is...>)
{
	return (*f)(std::get<Is>(t)...);
}

template<typename ReturnType, typename Tuple, typename... Args>
ReturnType CallByTupleRet(ReturnType(*f)(Args...), const Tuple& t)
{
	return CallByTupleImplRet(f, t, std::index_sequence_for<Args...>{});
}

template<typename ReturnType, typename... Args, typename Tuple, std::size_t... Is>
ReturnType CallByTupleImplRet(std::function<ReturnType(Args...)> f, const Tuple& t, std::index_sequence<Is...>)
{
	return f(std::get<Is>(t)...);
}

template<typename ReturnType, typename Tuple, typename... Args>
ReturnType CallByTupleRet(std::function<ReturnType (Args...)> f, const Tuple& t)
{
	return CallByTupleImplRet(f, t, std::index_sequence_for<Args...>{});
}

template <class Fn>
struct ArgsOfLambda;

template <class T, class Ret, class ... Args>
struct ArgsOfLambda<Ret(T::*)(Args...) const>
{
	using Tuple = std::tuple<std::decay_t<Args>...>;
	using Fun = std::function<void(Args...)>;
};



using PointChar = char*;
using CPointChar = const char*;

template<typename Tuple, std::size_t... Is>
bool TupleUnpackImpl(Tuple& v, CPointChar &cur, size_t &len, std::index_sequence<Is...>) {

	bool isSuccess = true;
	auto isOk = [&isSuccess](bool is)
	{
		if (!is)
		{
			isSuccess = false;
		}
	};
	std::initializer_list<int>{(isOk( proto::Unpack(std::get<Is>(v), cur, len) ), 0)...};
	return isSuccess;
}

template<class ... Args >
bool UnpackTuple(std::tuple<Args...> &v, CPointChar &cur, size_t &len)
{
	return TupleUnpackImpl(v, cur, len, std::index_sequence_for<Args...>{});
}

//rpc 服务端实现
//@Con 网络连接对象类型
template<class Con>
class RpcSvrImp 
{
public:
	using SendFun = std::function<void(Con &con, const char *data, size_t len)>;
	using SvrFun = std::function<void(const char *data, size_t len)>;
	struct FunData
	{
		SvrFun fun = nullptr;
		std::string name;
	};

private:

	std::vector<FunData> m_id2Fun;
	std::set<std::string> m_regName;
	uint32_t m_curSnId     = 0;      //当前处理的 请求响应会话id
	Con*     m_curCon      = nullptr;//当前处理的 连接对象
	SendFun  m_send        = nullptr;

public:
	RpcSvrImp() {
		m_id2Fun.resize(CUSTOM_FUN_ID); //idx <CUSTOM_FUN_ID 空内容
	};

	void Init(SendFun send) { m_send = send; }

	void GetName2Id(std::map<std::string, uint32_t> &name2Id) const
	{
		for (size_t i = CUSTOM_FUN_ID; i < m_id2Fun.size(); ++i)
		{
			name2Id[m_id2Fun[i].name] = i;
		}
	}
	const std::string GetNameById(size_t funid)
	{
		if (funid>= m_id2Fun.size())
		{
			return "";
		}
		return m_id2Fun[funid].name;
	}
	Con* GetCurCon() { return m_curCon; }
	uint32_t GetCurSnId() { return m_curSnId; }

	template<class ... Args>
	void RetEx(Con &con, uint32_t snId, Args&& ... args)
	{
		char *pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;

		L_COND_V(proto::Pack(RPC_RSP_ID, pBuf, len));
		L_COND_V(proto::Pack(snId, pBuf, len));
		bool isSuccess = true;
		auto isOk = [&isSuccess](bool is)
		{
			if (!is)
			{
				isSuccess = false;
			}
		};
		std::initializer_list<int> { (isOk(proto::Pack(std::forward<Args>(args), pBuf, len)), 0)... };
		L_COND_V(isSuccess);
		len = MAX_NET_BUF_LEN - len;

		m_send(con, rpc::gbuf, len);
	}

	void RetErrorLog(Con &con, uint32_t snId, const std::string &log)
	{
		char *pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;
		L_COND_V(proto::Pack(RPC_RSP_ERROR_ID, pBuf, len));
		L_COND_V(proto::Pack(snId, pBuf, len));
		L_COND_V(proto::Pack(log, pBuf, len));
		len = MAX_NET_BUF_LEN - len;
		m_send(con, rpc::gbuf, len);
	}

	template<class ... Args>
	void Ret(Args&& ... args)
	{
		L_COND_V(m_curCon, "can't call outside svr fun");
		L_COND_V(m_curSnId, "can't call outside svr fun");
		RetEx(*m_curCon, m_curSnId, std::forward<Args>(args)...);
	}

	void Rev(Con &con, const char *data, size_t len)
	{
		L_COND_V(m_send, "uninit rpc svr");

		m_curCon = &con;
		int32_t funId = -1;
		L_COND_V(proto::Unpack(funId, data, len));
		L_COND_V(proto::Unpack(m_curSnId, data, len));

		if ((size_t)funId >= m_id2Fun.size())
		{
			std::string log = "can't find fun id"; 
			log += std::to_string(funId);
			RetErrorLog(*m_curCon, m_curSnId, log);
			L_ERROR("%s", log.c_str());
			m_curSnId = 0;
			m_curCon = nullptr;
			return;
		}
		if (funId == RPC_INIT_ID)
		{
			std::map<std::string, uint32_t> name2Id;
			for (size_t i = 1; i < m_id2Fun.size(); ++i)
			{
				name2Id[m_id2Fun[i].name] = i;
			}
			RetEx(*m_curCon, m_curSnId, name2Id);
			m_curSnId = 0;
			m_curCon = nullptr;
			return;
		}
		(m_id2Fun[funId].fun)(data, len);
		m_curSnId = 0;
		m_curCon = nullptr;
	}


	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...), const std::string &name)
	{
		L_COND_V(m_regName.insert(name).second, "repeated reg fun %s", name.c_str());
		SvrFun svrFun = [this, f, name](const char *data, size_t len)
		{
			std::tuple<std::decay_t<Args>...> t;
			if (!UnpackTuple(t, data, len))
			{
				L_ERROR("client req para illegal. name=%s", name.c_str());
				std::stringstream ss;
				ss << "you req para illegal. name=" << name;
				RetErrorLog(*m_curCon, m_curSnId, ss.str());//请求参数错误。 网络消息非法，解析参数失败. 
				return;
			}
			L_COND_V(len == 0, "fun name=%s", name.c_str());

			if constexpr (std::is_same<ReturnType, void>::value) {
				CallByTupleRet(f, t);
			}
			else {
				ReturnType ret = CallByTupleRet(f, t);
				Ret(ret);
			}
		};
		
		m_id2Fun.push_back({ svrFun , name });
	}	

	//用ID注册， 为client高效远程调用提供支持
	//注意： 违反下面事项，会报错
	//1 必须保证先调用所有ID注册，才能调用字符串注册。
	//2 注册ID必须从 CUSTOM_FUN_ID 开始，逐步增加。 
	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...),  char cmdId)
	{
		L_COND_V(cmdId >= (char)CUSTOM_FUN_ID, "CmdId must <= CUSTOM_FUN_ID");
		L_COND_V((size_t)cmdId == m_id2Fun.size());
		std::string name(1, cmdId);
		L_COND_V(m_regName.insert(name).second, "repeated reg fun %s", name.c_str());
		SvrFun svrFun = [this, f, cmdId, name](const char* data, size_t len)
		{
			std::tuple<std::decay_t<Args>...> t;
			if (!UnpackTuple(t, data, len))
			{
				L_ERROR("client req para illegal. cmdId=%d", (uint16_t)cmdId);
				std::stringstream ss;
				ss << "you req para illegal. cmdId=" << (uint16_t)cmdId;
				RetErrorLog(*m_curCon, m_curSnId, ss.str());//请求参数错误。 网络消息非法，解析参数失败. 
				return;
			}
			L_COND_V(len == 0, "fun name=%s", name.c_str());

			if constexpr (std::is_same<ReturnType, void>::value) {
				CallByTupleRet(f, t);
			}
			else {
				ReturnType ret = CallByTupleRet(f, t);
				Ret(ret);
			}
		};

		m_id2Fun.push_back({ svrFun , name });
	}

	//@obj 需要用户保证不野
	template<typename ReturnType, typename Obj, typename... Args>
	void RegFun(ReturnType(Obj::* memFun)(Args...), Obj &obj, const std::string &name)
	{
		std::function<ReturnType(Args...)> f = [&obj, memFun](Args&& ... args)
		{
			return (obj.*memFun)(std::forward<Args>(args) ...);
		};

		L_COND_V(m_regName.insert(name).second, "repeated reg fun %s", name.c_str());
		SvrFun svrFun = [this, f, name](const char* data, size_t len)
		{
			std::tuple<std::decay_t<Args>...> t;
			if (!UnpackTuple(t, data, len))
			{
				L_ERROR("client req para illegal. name=%s", name.c_str());
				std::stringstream ss;
				ss << "you req para illegal. fun name=" << name;
				RetErrorLog(*m_curCon, m_curSnId, ss.str());//请求参数错误。 网络消息非法，解析参数失败. 
				return;
			}
			L_COND_V(len == 0, "parse args error. fun name=%s", name.c_str());



			if constexpr (std::is_same<ReturnType, void>::value) {
				CallByTupleRet(f, t);
			}
			else {
				ReturnType ret = CallByTupleRet(f, t);
				Ret(ret);
			}
		};

		m_id2Fun.push_back({ svrFun , name });
	}
};

//rpc 客户端实现
class RpcClientImp
{
public:
	using RpcRspFun = std::function<void(const char* data, size_t len)>;
	using RpcSendFun = std::function<void(const char* data, size_t len)>;
	using RpcTimeOut = std::function<void()>;
	using ConInitOk = std::function<void()>;
	struct ReqData
	{
		RpcRspFun	rsp    = nullptr;
		RpcTimeOut timeOut = nullptr;
		uint32_t snId      = 0; //标识一次请求 响应 的会话。
		int64_t createSec  = 0;
		std::string funName;
	};

private:
	uint32_t	  m_snSeed  = 0;
	RpcSendFun    m_sendFun = nullptr;
	ConInitOk m_conInitOk = nullptr; //协议初始化完成调用
	bool m_isInit = false;
	std::map<std::string, uint32_t> m_str2FunId;
	std::deque<ReqData> m_dequeReq;

public:
	~RpcClientImp()
	{
		CheckTimeOut(0);
	}

	void Init(RpcSendFun send, ConInitOk conInitOk = nullptr)
	{
		m_sendFun = send;
		m_conInitOk = conInitOk;
	}

	bool IsInit()//true表示完整初始化，已请求svr获取初始信息
	{
		return m_isInit;
	}

	void SetStr2FunId(const std::map<std::string, uint32_t> &str2FunId)
	{
		m_str2FunId.clear();
		m_str2FunId = str2FunId;
		m_isInit = true;
	}

	void CheckTimeOut(uint64_t timeOutSec= RPC_TIME_OUT_SEC)
	{
		uint64_t cur = time(nullptr);
		for (auto it = m_dequeReq.begin(); it != m_dequeReq.end();)
		{
			if (cur - it->createSec >= timeOutSec)
			{
				if (it->timeOut)
				{
					it->timeOut();
				}
				it = m_dequeReq.erase(it);
				L_ERROR("session timer out. snid=%d name=%s", it->snId, it->funName.c_str(), "timeOutSec=%ld", timeOutSec, "cur - it->createSec=%ld", cur - it->createSec);
			}
			else
			{
				++it;
			}
		}
	}

	//@cb 为lambda表达式 或者函数对象 .
	template<class RspCb, class ... Args>
	void CallTimeOut(RspCb cb, RpcTimeOut timeOut, const std::string &funName, Args&& ... args)
	{
		L_COND_V(m_sendFun, "uninit send function");
		L_COND_V(IsInit(), "uninit, wait finish call ReqInit function");
		auto it = m_str2FunId.find(funName);
		if (it == m_str2FunId.end())
		{
			L_ERROR("can't find fun = %s", funName.c_str());
			return;
		}
		auto f = [cb, funName](const char *data, size_t len)
		{
			if constexpr (std::is_same<RspCb, decltype(nullptr)>::value)
			{
				return;//服务函数定义void 就不会跑这里。 服务器有返回，client不需要就跑这里。
			}
			else
			{
				//lambda 表达式转为 函数对象，统一处理。 为了判断空 函数对象
				class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Fun cbEx(cb);
				if (cbEx)
				{
					class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Tuple retTuple;
					L_COND_V(UnpackTuple(retTuple, data, len), "svr rsp para is illegal"); //解析参数失败
					L_COND_V(len == 0, "svr rsp para is illegal. fun name %s", funName.c_str()); //svr 返回参数非法
					CallByTuple(cb, retTuple);
				}
			}
		};
	
		uint32_t snId = NewSnId();

		{//没传入返回函数，忽略 登记  m_dequeReq
			bool isWaitRet = true;
			if constexpr (std::is_same<RspCb, decltype(nullptr)>::value)
			{
				isWaitRet = false;
			}
			else
			{
				//lambda 表达式转为 函数对象，统一处理。 为了判断空 函数对象
				class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Fun cbEx(cb);
				if (!cbEx)
				{
					isWaitRet = false;
				}
			}
			if (isWaitRet)
			{
				m_dequeReq.push_back({ f, timeOut, snId, time(nullptr), funName });
				if (m_dequeReq.size() > MAX_RPC_CACHE_SN_NUM)
				{
					L_ERROR("call cache is too more. cur fun=%s", funName.c_str());
					for (auto& v : m_dequeReq)
					{
						L_WARN("cache funname=%s", v.funName.c_str());
					}
					CheckTimeOut(RPC_TIME_OUT_SEC);
				}
			}
		}

		char *pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;
		L_COND_V(proto::Pack(it->second, pBuf, len));
		L_COND_V(proto::Pack(snId, pBuf, len));

		{
			bool isSuccess = true;
			auto isOk = [&isSuccess](bool is)
			{
				if (!is)
				{
					isSuccess = false;
				}
			};
			std::initializer_list<int> { (isOk(proto::Pack(std::forward<Args>(args), pBuf, len)), 0)... };
			L_COND_V(isSuccess);
		}

		size_t bufLen = MAX_NET_BUF_LEN - len;

		m_sendFun(rpc::gbuf, bufLen);
	}


	//支持lambda 写后面的辅助类，不建议保存对象。用临时对象就好了。
	//待优化，不用这种方式， 用更效率方式，比如 Call( CObj(arg.....), ret()); 就少点复制内存了。
	struct CallRetHelper 
	{
		using RpcTimeOut = std::function<void()>;
		uint32_t snId = 0;
		RpcClientImp* imp = nullptr;
		std::string funName;
		template<class RspCb>
		void Ret(RspCb cb, RpcTimeOut timeOut = nullptr)
		{
			if (nullptr == imp)
			{
				return;
			}
			auto f = [cb, funName=this->funName](const char* data, size_t len)
			{
				//lambda 表达式转为 函数对象，统一处理。 为了判断空 函数对象
				class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Fun cbEx(cb);
				if (cbEx)
				{
					class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Tuple retTuple;
					L_COND_V(UnpackTuple(retTuple, data, len), "svr rsp para is illegal"); //解析参数失败
					L_COND_V(len == 0, "svr rsp para is illegal. funName=%s", funName.c_str()); //svr 返回参数非法
					CallByTuple(cb, retTuple);
				}
			};

			imp->m_dequeReq.push_back({ f, timeOut, snId, time(nullptr),funName });
			if (imp->m_dequeReq.size() > MAX_RPC_CACHE_SN_NUM)
			{
				L_WARN("call cache is too more");
				imp->CheckTimeOut(RPC_TIME_OUT_SEC);
			}
			imp = nullptr;
		}
		template<class RspCb>
		void operator=(RspCb cb)
		{
			Ret(cb);
		}
	};

	//CallRet(...).ret(cb,timeOut) 版本， 支持lambda 写后面. 让代码更容易阅读
	//注意返回值别保存超过当前堆栈
	template<class ... Args>
	CallRetHelper CallRet(const std::string& funName, Args&& ... args)
	{
		CallRetHelper ret;
		L_COND(m_sendFun, ret, "uninit send function");
		L_COND(IsInit(), ret, "uninit, wait finish call ReqInit function");
		auto it = m_str2FunId.find(funName);
		if (it == m_str2FunId.end())
		{
			L_ERROR("can't find fun = %s", funName.c_str());
			return ret;
		}
	
		uint32_t snId = NewSnId();

		char* pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;
		L_COND(proto::Pack(it->second, pBuf, len), ret);
		L_COND(proto::Pack(snId, pBuf, len), ret);

		{
			bool isSuccess = true;
			auto isOk = [&isSuccess](bool is)
			{
				if (!is)
				{
					isSuccess = false;
				}
			};
			std::initializer_list<int> { (isOk(proto::Pack(std::forward<Args>(args), pBuf, len)), 0)... };
			L_COND(isSuccess, ret);
		}

		size_t bufLen = MAX_NET_BUF_LEN - len;

		m_sendFun(rpc::gbuf, bufLen);
		ret.snId = snId;
		ret.imp = this;
		ret.funName = funName;
		return ret;
	}

	//@cb 为lambda表达式 或者函数对象 .
	template<class RspCb, class ... Args>
	void CallTimeOut(RspCb cb, RpcTimeOut timeOut, char cmdId, Args&& ... args)
	{
		L_COND_V(m_sendFun, "uninit send function");
		L_COND_V(IsInit(), "uninit, wait finish call ReqInit function");
		auto f = [cb, cmdId](const char* data, size_t len)
		{
			if constexpr (std::is_same<RspCb, decltype(nullptr)>::value)
			{
				return;//服务函数定义void 就不会跑这里。 服务器有返回，client不需要就跑这里。
			}
			else
			{
				//lambda 表达式转为 函数对象，统一处理。 为了判断空 函数对象
				class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Fun cbEx(cb);
				if (cbEx)
				{
					class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Tuple retTuple;
					L_COND_V(UnpackTuple(retTuple, data, len), "svr rsp para is illegal"); //解析参数失败
					L_COND_V(len == 0, "svr rsp para is illegal. cmdId=%d", cmdId); //svr 返回参数非法
					CallByTuple(cb, retTuple);
				}
			}
		};

		uint32_t snId = NewSnId();
		{//没传入返回函数，忽略 登记  m_dequeReq
			bool isWaitRet = true;
			if constexpr (std::is_same<RspCb, decltype(nullptr)>::value)
			{
				isWaitRet = false;
			}
			else
			{
				//lambda 表达式转为 函数对象，统一处理。 为了判断空 函数对象
				class ArgsOfLambda<decltype(&decltype(cb)::operator())>::Fun cbEx(cb);
				if (!cbEx)
				{
					isWaitRet = false;
				}
			}
			if (isWaitRet)
			{
				std::string funName = "CmdId="+ std::to_string(cmdId);
				m_dequeReq.push_back({ f, timeOut, snId, time(nullptr), funName });
				if (m_dequeReq.size() > MAX_RPC_CACHE_SN_NUM)
				{
					L_WARN("call cache is too more");
					CheckTimeOut(RPC_TIME_OUT_SEC);
				}
			}
		}
		char* pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;
		L_COND_V(proto::Pack((uint32_t)cmdId, pBuf, len));
		L_COND_V(proto::Pack(snId, pBuf, len));

		{
			bool isSuccess = true;
			auto isOk = [&isSuccess](bool is)
			{
				if (!is)
				{
					isSuccess = false;
				}
			};
			std::initializer_list<int> { (isOk(proto::Pack(std::forward<Args>(args), pBuf, len)), 0)... };
			L_COND_V(isSuccess);
		}

		size_t bufLen = MAX_NET_BUF_LEN - len;

		m_sendFun(rpc::gbuf, bufLen);
	}

	void Rev(const char *data, size_t len)
	{
		if (m_dequeReq.empty())//无需处理返回
		{
			return;
		}

		uint32_t snid = 0;
		uint32_t id = 0;
		L_COND_V(proto::Unpack(id, data, len));
		L_COND_V(proto::Unpack(snid, data, len));

		if (id == RPC_RSP_ERROR_ID)
		{
			std::string log;
			L_COND_V(proto::Unpack(log, data, len));
			L_ERROR("rpc server : %s", log.c_str());
			return;
		}
		auto beginIt = m_dequeReq.begin();
		if (beginIt->snId == snid)
		{
			beginIt->rsp(data, len);
			m_dequeReq.pop_front();
			return;
		}

		for (auto it = m_dequeReq.begin(); it != m_dequeReq.end(); ++it)
		{
			if (it->snId == snid)
			{
				it->rsp(data, len);
				m_dequeReq.erase(it);
				return;
			}
		}
	}

	void ReqInit(const std::map<std::string, uint32_t> &name2Id)
	{
		L_COND_V (m_sendFun, "uninit send function");
		auto f = [this](const char *data, size_t len)
		{
			m_str2FunId.clear();
			proto::Unpack(m_str2FunId, data, len);
			m_isInit = true;
			L_COND_V(len == 0);
			if (m_conInitOk)
			{
				this->m_conInitOk();
			}
		};

		uint32_t snId = NewSnId();
		m_dequeReq.push_back({ f, nullptr, snId, time(nullptr), "ReqInit"});

		char *pBuf = rpc::gbuf;
		size_t len = MAX_NET_BUF_LEN;
		proto::Pack(RPC_INIT_ID, pBuf, len);
		proto::Pack(snId, pBuf, len);
		proto::Pack(name2Id, pBuf, len);
		m_sendFun(rpc::gbuf, MAX_NET_BUF_LEN - len);
	}

private:
	uint32_t NewSnId()
	{
		++m_snSeed;
		if (m_snSeed == 0)
		{
			m_snSeed = 1;
		}
		return m_snSeed;
	}
};


//Con 要求有 uint64_t Con::GetId() const;
template<class Con>
class RpcSvr 
{
private:
	RpcSvrImp<Con> m_svr;
	std::map<uint64_t, RpcClientImp> m_id2client; //管理svr作为 rpc client 的多个Con的 RpcClientImp
	Con *m_curReqCon = nullptr; //辅助解决  RpcClientImp 发送获取不到当前Con
	typename RpcSvrImp<Con>::SendFun m_send = nullptr;
	std::function<void(Con&)> m_conInitOk = nullptr;

public:
	//static RpcSvr &Ins()// //针对三消项目用，别的项目不建议用单例
	//{
	//	static RpcSvr *obj = new RpcSvr();
	//	return *obj;
	//}
	//@send 发送到客户端的实现函数
	//@conInitOk 客户端连接流程完成后调用
	void Init(typename RpcSvrImp<Con>::SendFun send, std::function<void(Con&)> conInitOk = nullptr)
	{
		m_svr.Init(send);
		m_send = send;
		m_conInitOk = conInitOk;
	}
	const std::string GetNameById(size_t funid)
	{
		return m_svr.GetNameById(funid);
	}
	void Connect(Con &con)
	{
		auto ret = m_id2client.emplace(con.GetId(), RpcClientImp());
		L_COND_V(ret.second, "add repeated con id %lx", con.GetId());
		RpcClientImp &client = ret.first->second;
		auto sendReq = [this](const char *data, size_t len)
		{
			L_COND_V(m_curReqCon);
			m_send(*m_curReqCon, data, len);
		};
		client.Init(sendReq);
	}

	void Discon(uint64_t id)
	{
		auto it = m_id2client.find(id);
		if(it != m_id2client.end())
		{
			it->second.CheckTimeOut(0);
			m_id2client.erase(id);
		}
	}

	template<class RspCb, class ... Args>
	void CallTimeOut(Con &con, RspCb cb, RpcClientImp::RpcTimeOut timeOut, const std::string &funName, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(cb, timeOut, funName, std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	template<class RspCb, class ... Args>
	void CallTimeOut(Con& con, RspCb cb, RpcClientImp::RpcTimeOut timeOut, char cmd, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(cb, timeOut, cmd, std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	template<class RspCb, class ... Args>
	void Call(Con &con, RspCb cb, const std::string &funName, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(cb, nullptr, funName, std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	template<class RspCb, class ... Args>
	void Call(Con& con, RspCb cb, char cmdId, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(cb, nullptr, cmdId, std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	template<class ... Args>
	RpcClientImp::CallRetHelper CallRet(Con &con, const char *funName, Args&& ... args)
	{
		RpcClientImp::CallRetHelper ret;
		auto it = m_id2client.find(con.GetId());
		L_COND(it != m_id2client.end(), ret);

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		ret = it->second.CallRet(std::string(funName), std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
		return ret;
	}

	template<class ... Args>
	void Call(Con &con, const char *funName, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(nullptr, nullptr, std::string(funName), std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	//Call("fun", const string&) 会重载歧义，提供这个准确区分的函数
	template<class ... Args>
	void CallNoRet(Con& con, const std::string& funName, Args&& ... args)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());

		m_curReqCon = &con;//缓存 con, CallTimeOut里面发送函数需要用到
		it->second.CallTimeOut(nullptr, nullptr, funName, std::forward<Args>(args) ...);
		m_curReqCon = nullptr;
	}

	//预览获取fun id
	//return 》=0 表示成功
	size_t PeedFunId(const char* data, size_t len)
	{
		int32_t funId = -1;
		L_COND(proto::Unpack(funId, data, len), -1);
		if (funId >= CUSTOM_FUN_ID)
		{
			return funId;
		}
		return -1;
	}

	void Rev(Con &con, const char *data, size_t len)
	{
		auto it = m_id2client.find(con.GetId());
		L_COND_V(it != m_id2client.end());
		RpcClientImp &client = it->second;
		//peed req id
		uint32_t reqId = 0;
		{
			const char* pBuf = data;
			size_t lenTmp = len;
			L_COND_V(proto::Unpack(reqId, pBuf, lenTmp));
		}
		if (reqId == RPC_RSP_ID || reqId == RPC_RSP_ERROR_ID)
		{
			client.Rev(data, len);
		}
		else if (reqId == RPC_INIT_ID)
		{
			{//peed client svr fun info
				uint32_t id = -1;
				uint32_t snId = 0;
				const char* pBuf = data;
				size_t lenTmp = len;
				L_COND_V(proto::Unpack(id, pBuf, lenTmp));
				L_COND_V(proto::Unpack(snId, pBuf, lenTmp));
				std::map<std::string, uint32_t> revName2Id;
				L_COND_V(proto::Unpack(revName2Id, pBuf, lenTmp));
				client.SetStr2FunId(revName2Id);
			}
			m_svr.Rev(con, data, len);
			if (m_conInitOk)
			{
				m_conInitOk(con);
			}
		}
		else
		{
			m_svr.Rev(con, data, len);
		}
	}

	void CheckTimeOut(uint64_t timeOutSec = RPC_TIME_OUT_SEC)
	{
		for (auto &v : m_id2client)
		{
			v.second.CheckTimeOut(timeOutSec);
		}
	}

	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...), const std::string &name)
	{
		m_svr.RegFun(f, name);
	}

	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...), char cmdId)
	{
		m_svr.RegFun(f, cmdId);
	}

	template<typename ReturnType, typename Obj, typename... Args>
	void RegFun(ReturnType(Obj::* memFun)(Args...), Obj& obj, const std::string& name)
	{
		m_svr.RegFun(memFun, obj, name);
	}

	template<class ... Args>
	void RetEx(Con& con, uint32_t snId, Args&& ... args)
	{
		m_svr.RetEx(con, snId, std::forward<Args>(args)...);
	}

	template<class ... Args>
	void Ret(Args&& ... args)
	{
		m_svr.Ret(std::forward<Args>(args)...);
	}

	uint32_t GetCurSnId()
	{
		return m_svr.GetCurSnId();
	}
	Con* GetCurCon()
	{
		return m_svr.GetCurCon();
	}
};


class RpcClient
{
private:
	RpcSvrImp<int> m_svr;
	RpcClientImp m_client;

public:
	//@send 发送到服务器的实现函数
	//@initOkFun 连接流程完成后调用函数
	void Init(typename RpcClientImp::RpcSendFun send, typename RpcClientImp::ConInitOk initOkFun = nullptr) {
		auto SendRsp = [send](int &con, const char *data, size_t len)
		{
			send(data, len);
		};
		m_svr.Init(SendRsp);
		m_client.Init(send, initOkFun);
	}

	bool IsInit()
	{
		return m_client.IsInit();
	}

	void ReqInit()
	{
		std::map<std::string, uint32_t> name2Id;
		m_svr.GetName2Id(name2Id);
		m_client.ReqInit(name2Id);
	}

	//@cb 为lambda表达式 或者函数对象 .  
	template<class RspCb, class ... Args>
	void CallTimeOut(RspCb cb, RpcClientImp::RpcTimeOut timeOut, const std::string &funName, Args&& ... args)
	{
		m_client.CallTimeOut(cb, timeOut, funName, std::forward<Args>(args) ...);
	}
	
	template<class RspCb, class ... Args>
	void Call(RspCb cb, const std::string &funName, Args&& ... args)
	{
		m_client.CallTimeOut(cb, nullptr, funName, std::forward<Args>(args) ...);
	}

	template<class RspCb, class ... Args>
	void CallTimeOut(RspCb cb, RpcClientImp::RpcTimeOut timeOut, char cmdId, Args&& ... args)
	{
		m_client.CallTimeOut(cb, timeOut, cmdId, std::forward<Args>(args) ...);
	}

	template<class RspCb, class ... Args>
	void Call(RspCb cb, char cmdId, Args&& ... args)
	{
		m_client.CallTimeOut(cb, nullptr, cmdId, std::forward<Args>(args) ...);
	}

	template<class ... Args>
	RpcClientImp::CallRetHelper CallRet(const std::string& funName, Args&& ... args)
	{
		return m_client.CallRet(funName, std::forward<Args>(args) ...);
	}

	template<class ... Args>
	void Call(const char *funName, Args&& ... args)
	{
		m_client.CallTimeOut(nullptr, nullptr, std::string(funName), std::forward<Args>(args) ...);
	}
	template<class ... Args>
	void Call(char cmdId, Args&& ... args)
	{
		m_client.CallTimeOut(nullptr, nullptr, cmdId, std::forward<Args>(args) ...);
	}

	//Call("fun", const string&) 会重载歧义，提供这个准确区分的函数
	template<class ... Args>
	void CallNoRet(const std::string& funName, Args&& ... args)
	{
		m_client.CallTimeOut(nullptr, nullptr, funName, std::forward<Args>(args) ...);
	}
	//template<class ... Args>
	//void CallNoRet(char cmdId, Args&& ... args)
	//{
	//	m_client.CallTimeOut(nullptr, nullptr, cmdId, std::forward<Args>(args) ...);
	//}

	void Rev(const char *data, size_t len)
	{
		const char *pBuf = data;
		size_t lenTmp = len;
		uint32_t id = 0;
		L_COND_V(proto::Unpack(id, pBuf, lenTmp));
		if (id == RPC_RSP_ID || id == RPC_RSP_ERROR_ID)
		{
			m_client.Rev(data, len);
		}
		else
		{
			int con = 0;
			m_svr.Rev(con, data, len);
		}
	}

	void CheckTimeOut(uint64_t timeOutSec = RPC_TIME_OUT_SEC)
	{
		m_client.CheckTimeOut(timeOutSec);
	}

	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...), const std::string &name)
	{
		m_svr.RegFun(f, name);
	}
	template<typename ReturnType, typename... Args>
	void RegFun(ReturnType(*f)(Args...), char cmdId)
	{
		m_svr.RegFun(f, cmdId);
	}

	template<typename ReturnType, typename Obj, typename... Args>
	void RegFun(ReturnType(Obj::* memFun)(Args...), Obj& obj, const std::string& name)
	{
		m_svr.RegFun(memFun, obj, name);
	}

	//可服务器函数外调用，支持异步返回
	template<class ... Args>
	void RetEx(uint32_t snId, Args&& ... args)
	{
		int t = 0;
		m_svr.RetEx(t, snId, std::forward<Args>(args)...);
	}

	//只能服务器函数内部调用
	template<class ... Args>
	void Ret(Args&& ... args)
	{
		m_svr.Ret(std::forward<Args>(args)...);
	}

	uint32_t GetCurSnId()
	{
		return m_svr.GetCurSnId();
	}

};


//静态执行
#define STATIC_RUN_CAT(name, exe)\
namespace {\
	struct StaticRunReg##name\
	{\
		StaticRunReg##name()\
		{\
		 exe;\
		}\
	};\
	static StaticRunReg##name _StaticRunReg##name;\
}

//多一层，避免__LINE__直接变化成字符串"__LINE__"
#define STATIC_RUN_LINE(line, exe) STATIC_RUN_CAT(line, exe)
#define STATIC_RUN(exe) STATIC_RUN_LINE(__LINE__, exe)

//简化注册全局函数，参考用，具体项目需要修改
#define RpcReg(fun) STATIC_RUN( RpcSvr<Con>::Ins().RegFun(fun, #fun);) 